#pragma once
#include "HashTable.hpp"
#include "stringObject.hpp"

namespace redisStruct
{
    template <>
    struct Hash<stringObject*>
    {
        size_t operator()(stringObject* str_obj)
        {
            if (str_obj->_encoding == TYPE_Encoding_INT)
                return (size_t)str_obj->_ptr;

            // BKDR
            size_t value = 0;
            for (int i = 0; i < str_obj->_size; i++)
            {
                value *= 31;
                value += str_obj->_ptr[i];
            }
            return value;
        }
    };
    template <>
    struct Equal<stringObject*>
    {
        bool operator()(const stringObject* str_obj1, const stringObject* str_obj2) const
        {
            return *str_obj1 == *str_obj2;
        }
    };

    template <class T>
    struct CopyOfT
    {
        T operator()(const T& t)
        {
            return t;
        }
    };
    template <>
    struct CopyOfT<redisObject*>
    {
        redisObject* operator()(redisObject* obj) const
        {
            obj->incrRefCount();
            return obj;
        }
    };
    template <>
    struct CopyOfT<stringObject*>
    {
        stringObject* operator()(stringObject* obj) const
        {
            obj->incrRefCount();
            return obj;
        }
    };

    template <class Key, class Val, class CopyOfK, class CopyOfV>
    struct CopyOfKV
    {
        pair<Key, Val> operator()(const pair<Key, Val>& kv)
        {
            pair<Key, Val> p;
            p.first = CopyOfK()(kv.first);
            p.second = CopyOfV()(kv.second);
            return p;
        }
    };

    template <class T>
    struct FreeOfT
    {
        void operator()(const T& t)
        {
            return;
        }
    };
    template <>
    struct FreeOfT<redisObject*>
    {
        void operator()(redisObject* obj)
        {
            obj->decrRefCount();
            return;
        }
    };
    template <>
    struct FreeOfT<stringObject*>
    {
        void operator()(stringObject* obj)
        {
            obj->decrRefCount();
            return;
        }
    };

    template <class Key, class Val, class FreeOfKey, class FreeOfVal>
    struct FreeOfKV
    {
        void operator()(const pair<Key, Val>& kv)
        {
            FreeOfKey()(kv.first);
            FreeOfVal()(kv.second);
        }
    };

    template <class Key, class Val, class HashFunc = Hash<Key>, class EqualOfK = Equal<Key>,
        class CopyOfK = CopyOfT<Key>, class CopyOfV = CopyOfT<Val>,
        class FreeOfK = FreeOfT<Key>, class FreeOfV = FreeOfT<Val>>
        class unordered_map 
    {
        struct KOfT
        {
            const Key& operator()(const pair<Key, Val>& p)
            {
                return p.first;
            }
        };

    private:
        HashTable<Key, pair<Key, Val>, KOfT, HashFunc, EqualOfK, CopyOfKV<Key, Val, CopyOfK, CopyOfV>, FreeOfKV<Key, Val, FreeOfK, FreeOfV>> _ht;

    public:
        typedef typename HashTable<Key, pair<Key, Val>, KOfT, HashFunc, EqualOfK, CopyOfKV<Key, Val, CopyOfK, CopyOfV>, FreeOfKV<Key, Val, FreeOfK, FreeOfV>>::iterator iterator;
        typedef typename HashTable<Key, pair<Key, Val>, KOfT, HashFunc, EqualOfK, CopyOfKV<Key, Val, CopyOfK, CopyOfV>, FreeOfKV<Key, Val, FreeOfK, FreeOfV>>::const_iterator const_iterator;

    public:
        unordered_map()  {};
        ~unordered_map()
        {
            //cout << "~Dict()" << endl;
        };
        size_t size() const
        {
            _ht.size();
        }
        iterator begin()
        {
            return _ht.begin();
        }
        const_iterator begin() const
        {
            return _ht.begin();
        }
        iterator end()
        {
            return _ht.end();
        }
        const_iterator end() const
        {
            return _ht.end();
        }
        iterator find(const Key& key) // 只能读，想修改请调用replace
        {
            return _ht.find(key);
        }
        pair<iterator, bool> insert(const pair<Key, Val>& p)
        {
            return _ht.insert(p);
        }
        bool erase(const Key& key)
        {
            return _ht.erase(key) != _ht.end();
        }
        void replace(const pair<Key, Val>& kv)
        {
            auto iter = _ht.find(kv.first);

            if (iter == end())
            {
                insert(kv);
            }
            else
            {

                FreeOfV()(iter->second);
                iter->second = CopyOfV()(kv.second);
            }
        }
        /*Val& operator[](const Key& key)
        {
            auto ret = insert(make_pair(key,Val()));
            return ret.first->second;
        }
        */
        /*const Val& operator[](const Key& key) const
        {
            auto ret = insert(make_pair(key, Val()));
            return ret.first->second;
        }
        */
    };

    void test_map()
    {
        unordered_map<stringObject*, redisObject*> dict;
        stringObject* o1 = new stringObject("123", 3);
        stringObject* o2 = new stringObject("12s", 3);
        stringObject* o3 = new stringObject("123", 3);
        stringObject* o4 = new stringObject("dsads", 5);

        dict.insert(make_pair(o1, o2));

        o1->decrRefCount();
        o2->decrRefCount();
        o3->decrRefCount();
        o4->decrRefCount();
        // hash.replace(make_pair(o1, o4));

        stringObject* oo1 = new stringObject("123", 3);
        auto iter = dict.find(oo1);
        const stringObject* str1 = (stringObject*)iter->second;
        cout << str1->c_str() << endl;
    }

}